import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:xsdk_flutter/xsdk/framework/bean/x_bean_device.dart';
import 'package:xsdk_flutter/xsdk/utils/queue/x_bean_queue_message.dart';
import 'package:xsdk_flutter/xsdk/operation/x_mixin_release.dart';
import 'package:xsdk_flutter/xsdk/utils/socket/base/x_socket_connect_item.dart';
import 'package:xsdk_flutter/xsdk/utils/socket/support/x_socket_notify_callback.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_flutter.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_log.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_string.dart';

/*
服务端ServerSocket
注意: flutter的手机端不支持Websocket(server== await HttpServer.bind(InternetAddress.anyIPv4, _serverPort);)

Android解决收到信息后自动断开的问题解决:
<application
...
 android:networkSecurityConfig="@xml/x_websocket_client_not_close"
...
    />

    Connect_error on MacOS with SocketException: Connection failed
Refer to https://github.com/flutter/flutter/issues/47606#issuecomment-568522318 issue.
By adding the following key into the to file *.entitlements under directory macos/Runner/

<key>com.apple.security.network.client</key>
<true/>

属于TCP协议; 如UDP则使用RawDatagramSocket


其他:
第三方库封装:socket_io_client, https://pub.flutter-io.cn/packages/socket_io_client


注意:在 Flutter 中，如果你在 iOS/Android 设备上使用 Server Socket，会遇到息屏后连接断开的情况。
这通常是因为 iOS 系统为了节省电池，在设备进入睡眠状态时会暂停网络活动。
实测没有任何断开回调通知,要解决这个问题,可以:
通过心跳包判断和重连

可以尝试其他几种方法：
在你的 iOS 应用**使用后台模式**： Info.plist 文件中，添加 UIBackgroundModes 键，并将其值设置为 audio 或 voip ，这可以让应用在后台继续运行。
  <key>UIBackgroundModes</key>
   <array>
       <string>audio</string>
   </array>

在 Android 中，**使用前台服务**：你可以创建一个前台服务来保持应用在后台运行。前台服务会显示一个持续的通知，这样系统就不会轻易杀死你的应用。
public class MyForegroundService extends Service {
       @Override
       public void onCreate() {
           super.onCreate();
           startForeground(1, new Notification());
       }
       @Override
       public int onStartCommand(Intent intent, int flags, int startId) {
           // 你的 Socket 逻辑
           return START_STICKY;
       }
       @Override
       public IBinder onBind(Intent intent) {
           return null;
       }
   }
 */
class XServerSocketAPI with XMixinRelease,WidgetsBindingObserver{

  late int serverPort;
  //注意:'localhost'或'127.0.0.1'只能由设备本身访问,外界设备访问失败报错!
  final String _serverAddress='0.0.0.0';

  ServerSocket? serverSocket;//服务端
  final List<XSocketConnectItem> clientSockets=[];

  //是否自动发送自定义心跳包
  XBaseDevice device;

  XServerSocketAPI(this.device){
    serverPort=device.port;
    if (serverPort <=1024){
      serverPort=2222;
    }
    /*
    监听 App 生命周期,需重写didChangeAppLifecycleState方法
    注意：这里app的生命周期并不是像 Android 那样页面切换的生命周期，而是监听点击 home、物理返回键、屏幕锁定和解锁;
    实测web端不适用?

    取消监听App 生命周期: WidgetsBinding.instance.removeObserver(this);
   */
    WidgetsBinding.instance.addObserver(this);
  }


  /*
  监听 App 生命周期(非web),重写方法实现  WidgetsBinding.instance.addObserver(this);
  注意：didChangeAppLifecycleState 管理的生命周期并不是像 Android 那样页面切换的生命周期，而是监听点击 home、物理返回键、屏幕锁定和解锁
   */
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.paused) {
      // The application is not currently visible to the user, not responding to
      // user input, and running in the background.
      // 进入后台, 不可见，不可操作
    }else if (state == AppLifecycleState.resumed) {
      // The application is visible and responding to user input.
      // 进入前台, 可见，可操作
      //XLogUtils.printLog('---监听App生命周期,resumed,可见,重新激活屏幕');
      if(XFlutterUtils.isiOS()){
        //实测:iOS锁屏或息屏,都会断开socket(且没回调通知,则通过监听app重新进入前台进行重新创建,走onDone()回调处理断链)
        _cleanAll();
      }
    }else if (state == AppLifecycleState.inactive) {
      // The application is in an inactive state and is not receiving user input.
      // 过渡时期，不可操作
    }else if (state == AppLifecycleState.detached) {
      // The application is still hosted on a flutter engine but is detached from any host views.
      // 虽然还在运行，但已经没有任何存在的界面。
    }

  }


  @override
  void xRelease() {
    //释放资源
    WidgetsBinding.instance.removeObserver(this);
    _isAutoReconnect=false;
    _cleanAll();
  }

  void _cleanAll(){
    device.isConnected=false;

    try {
      _timer_client?.cancel();
      _timer_ServerSocket?.cancel();

      //
      for(XSocketConnectItem socket in clientSockets){
        socket.xRelease();
      }
      //
      serverSocket?.close();

    }catch (error) {
      //
    }finally{
      clientSockets.clear();
      serverSocket=null;
      _timer_client = null;
      _timer_ServerSocket = null;
    }
  }

  //1.启动server socket
  void start() {

    //
    ServerSocket.bind(_serverAddress, serverPort).then((ServerSocket socketS){
      XLogUtils.printLog('---socket服务端启动成功!');
      serverSocket=socketS;
      device.isConnected=true;

      //开启监听
      //注意:socket.listen()只能订阅一次,会替代旧的
      //socket?.asBroadcastStream().listen() 使用多个订阅
      socketS.listen((Socket socket){
        XLogUtils.printLog('---服务端监听: client= ${socket.remoteAddress.address},${socket.remotePort},${socket.address.address},${socket.port}');
        //
        XSocketConnectItem socketItem=XSocketConnectItem(
          isServer:true,
          isCustomSocketCommunication:true,
          socket:socket,
          disconnectCallback:_handleClientDisconnect,
          device: device,
        );
        clientSockets.add(socketItem);
        XLogUtils.printLog('---新增clientSocket,共:${clientSockets.length}');
        XSocketDeviceNotifyCallback.instance.serverSocketDeviceConnectStatusCallback(clientSockets.length);
      },onDone: (){
        XLogUtils.printLog('---socket服务端onDone,断连');
        _handleServerDisconnect();
      }).onError((e){
        XLogUtils.printLog('---socket服务端listen, error= $e');
      }
      );

    }).onError((error, stackTrace){
      XLogUtils.printLog('---socket服务端bind, error= $error');
    });

  }

  //2.发送消息
  bool sendMessage(
      String? toClientIP,
      int? toClientPort,
      XBaseQueueMessage msg
      ) {
    if(!XStringUtils.isEmpty(toClientIP)){

      for(XSocketConnectItem client in clientSockets){
        try{
          if(toClientIP==client.ip && toClientPort==client.port){
            return client.sendMsg(msg);
          }
        }catch(e){
          //
        }
      }
    }

    return false;
  }

  //3.
  void sendAllClientSocketMessage(XBaseQueueMessage msg){
    for(XSocketConnectItem client in clientSockets){
      try{
        client.sendMsg(msg);
      }catch(e){
        //
      }
    }
  }

  ///////////////////////////////////////////////////////////////
  //处理客户端断连
  Timer? _timer_client;
  void _handleClientDisconnect(String? ip,int? port){
    //清除断连客户端连接,服务端不重连客户端
    XLogUtils.printLog('---清除断连客户端连接,服务端不重连客户端,现有:${clientSockets.length},ip=$ip,port=$port');
    _timer_client ??= Timer(const Duration(seconds: 2),(){
      //
      clientSockets.removeWhere((XSocketConnectItem element)=> element.socket==null);
      XLogUtils.printLog('---清除断连clientSocket,剩余:${clientSockets.length}');
      XSocketDeviceNotifyCallback.instance.serverSocketDeviceConnectStatusCallback(clientSockets.length);
      //
      _timer_client?.cancel();
      _timer_client = null;
    }
    );

  }


  //处理socket断连
  Timer? _timer_ServerSocket;
  bool _isAutoReconnect=true;
  void _handleServerDisconnect(){

    //自动重连
    if(_isAutoReconnect){
      //
      _cleanAll();
      //
      _timer_ServerSocket ??= Timer(const Duration(seconds: 3),(){
        XLogUtils.printLog('---自动重建ServerSocket');
        _timer_ServerSocket?.cancel();
        _timer_ServerSocket = null;
        //
        start();
      }
      );
    }
  }
  ///////////////////////////////////////////////////////////////

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
          other is XServerSocketAPI &&
              runtimeType == other.runtimeType &&
              serverPort == other.serverPort;

  @override
  int get hashCode => serverPort.hashCode;
}
